package cmpe451.group7.ourcity.recommendation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.htmlparser.jericho.Element;
import net.htmlparser.jericho.Source;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import cmpe451.group7.ourcity.entity.Tag;
import cmpe451.group7.ourcity.entity.TagSimilarity;

/**
 * Uses the N-Similarity web-service to find the similar words of a given word.
 * 
 * It also finds the similar adjectives, verbs
 */
public class SimilarityFinder {
	private static boolean ENABLE_ADJECTIVE_SEARCH = true;

	public static final String SIMILARITY_SERVICE = "http://swoogle.umbc.edu/SimService/GetSimilarity";
	private static final String DEFAULT_SIMILAR_WORD_COUNT = "15";
	private static Pattern pairPattern = Pattern.compile("(.*) ([\\d.]*)");

	public static List<TagSimilarity> findSimilarTags(String word) {
		String response;
		try {
			response = sendQuery(word);

			/*
			 * If there is an error, like noun-verb-adjective, return an empty
			 * list
			 */
			if (StringUtils.isEmpty(response))
				return new ArrayList<TagSimilarity>();
			else
				return extractTags(response);
		} catch (RecommendationException e) {
			return new ArrayList<TagSimilarity>();
		}

	}

	protected static String sendQuery(String word)
			throws RecommendationException {
		String res = "";

		String similarWords = sendQuery(word, DEFAULT_SIMILAR_WORD_COUNT,
				WordType.WORD);
		res += validResponse(similarWords) ? similarWords : "";

		if (ENABLE_ADJECTIVE_SEARCH) {
			String similarAdjectives = sendQuery(word,
					DEFAULT_SIMILAR_WORD_COUNT, WordType.ADJECTIVE);
			res += validResponse(similarAdjectives) ? similarAdjectives : "";
		}

		return res;
	}

	private static String sendQuery(String word, String count, WordType wordType)
			throws RecommendationException {
		HttpClient client = new DefaultHttpClient();
		HttpPost post = new HttpPost(SIMILARITY_SERVICE);

		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();

		nameValuePairs.add(new BasicNameValuePair("operation", "top_sim"));
		nameValuePairs.add(new BasicNameValuePair("word", word.toLowerCase()));
		nameValuePairs.add(new BasicNameValuePair("pos", wordType.formValue));
		nameValuePairs.add(new BasicNameValuePair("N", count));
		nameValuePairs.add(new BasicNameValuePair("sim_type", "concept"));
		nameValuePairs.add(new BasicNameValuePair("corpus", "webbase"));

		try {
			post.setEntity(new UrlEncodedFormEntity(nameValuePairs, "utf-8"));
			HttpResponse response = client.execute(post);
			String stringifiedResponse = EntityUtils.toString(response
					.getEntity());
			Source responseText = new Source(stringifiedResponse);
			Element textArea = responseText.getFirstElement("textarea");
			String textAreaContent = textArea.getContent().toString().trim();
			// remove the last comma
			textAreaContent = textAreaContent.substring(0,
					textAreaContent.length() - 1);
			return textAreaContent;
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

		throw new RecommendationException(
				"Error occured while connecting to the similarity web service");
	}

	protected static List<TagSimilarity> extractTags(String response) {
		String[] relatedWords = response.split(", ");
		List<TagSimilarity> tags = new ArrayList<TagSimilarity>();
		for (String w : relatedWords) {
			Matcher matcher = pairPattern.matcher(w);
			matcher.find();
			String key = matcher.group(1);
			key = key.substring(0, key.length() - 3);
			String value = matcher.group(2);

			Tag tag = FreebaseQuery.find(key);
			if (tag != null) {
				tags.add(new TagSimilarity(null, tag.getmID(), Double
						.parseDouble(value)));
			}

		}
		return tags;
	}

	private static boolean validResponse(String response) {
		return !response.startsWith("Warning");
	}
}

enum WordType {
	WORD("NN"), ADJECTIVE("JJ");

	String formValue;

	WordType(String formValue) {
		this.formValue = formValue;
	}
}
